package cn.tannn.tcache.core;

import cn.tannn.tcache.core.entry.CacheEntry;
import cn.tannn.tcache.core.entry.ZsetEntry;
import cn.tannn.tcache.util.RegexUtil;

import java.security.SecureRandom;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/**
 * 数据容器
 *
 * @author <a href="https://t.tannn.cn/">tnnn</a>
 * @version V1.0
 * @date 2024/6/15 下午8:23
 */
public class Tcache {
    /**
     * 缓存数据
     */
    Map<String, CacheEntry<?>> maps = new HashMap<>();


    /**
     * 随机数
     */
    SecureRandom random = new SecureRandom();

    /**
     * 找所有符合给定模式 pattern 的 key
     *
     * @param pattern 正则
     */
    public String[] keys(String pattern) {
        if (pattern == null) {
            return new String[0];
        }

        // 将 glob 模式转换为正则表达式
        String regex = RegexUtil.globToRegex(pattern);
        Pattern compiledPattern = Pattern.compile(regex);

        List<String> matchedKeys = new ArrayList<>();
        for (String key : maps.keySet()) {
            Matcher matcher = compiledPattern.matcher(key);
            if (matcher.matches()) {
                matchedKeys.add(key);
            }
        }
        return matchedKeys.toArray(String[]::new);
    }


    // =========================处理string类型 start==================================

    /**
     * 获取
     */
    public String get(String key) {
        CacheEntry<?> entry = maps.get(key);
        if (entry == null) {
            return null;
        } else {
            return (String) entry.getValue();
        }

    }

    /**
     * 存储
     */
    public void set(String key, String value) {
        maps.put(key, new CacheEntry<>(value));
    }

    /**
     * 根据Key删除
     */
    public int del(String... keys) {
        return keys == null ? 0 : (int) Arrays.stream(keys)
                .map(maps::remove).filter(Objects::nonNull).count();

    }

    /**
     * key是否存在
     */
    public int exists(String... keys) {
        return keys == null ? 0 : (int) Arrays.stream(keys)
                .map(maps::containsKey).filter(x -> x).count();
    }


    /**
     * 一次获取多个键的值 (multiple)
     */
    public String[] mget(String... keys) {
        return keys == null ? new String[0] : Arrays.stream(keys)
                .map(this::get).toArray(String[]::new);
    }

    /**
     * 一次设置多个键值对 (multiple)
     */
    public void mset(String[] keys, String... vals) {
        if (keys == null || keys.length == 0) {
            return;
        }
        for (int i = 0; i < keys.length; i++) {
            set(keys[i], vals[i]);
        }
    }

    /**
     * 递增 (默认从0开始)
     */
    public int incr(String key) {
        String str = get(key);
        int val = 0;
        try {
            if (str != null) {
                val = Integer.parseInt(str);
            }
            val++;
            set(key, String.valueOf(val));
        } catch (NumberFormatException nfe) {
            throw nfe;
        }
        return val;
    }

    /**
     * 递减(默认从0开始，递减会出现负数)
     */
    public int decr(String key) {
        String str = get(key);
        int val = 0;
        try {
            if (str != null) {
                val = Integer.parseInt(str);
            }
            val--;
            set(key, String.valueOf(val));
        } catch (NumberFormatException nfe) {
            throw nfe;
        }
        return val;
    }

    /**
     * 字符串值长度计算
     *
     * @param key key
     * @return 长度
     */
    public Integer strlen(String key) {
        return get(key) == null ? 0 : get(key).length();
    }

    // =========================处理string类型 end ==================================


    // =========================处理 list 类型 start ==================================

    /**
     * 一个key,往里插入多个元素
     *
     * @param key  key
     * @param type <p> true:先进后出,最后进去的在第一位(lpush)
     *             <p> false:先进先出,最后进去的在最后(rpush)
     * @param vals 多个元素
     * @return >0 成功
     */
    public Integer push(String key, boolean type, String... vals) {
        if (vals == null || vals.length == 0) {
            return 0;
        }
        CacheEntry<LinkedList<String>> entry = (CacheEntry<LinkedList<String>>) maps.get(key);
        if (entry == null) {
            entry = new CacheEntry<>(new LinkedList<>());
            maps.put(key, entry);
        }
        LinkedList<String> exist = entry.getValue();
        if (type) {
            // 头插
            Arrays.stream(vals).forEach(exist::addFirst);
        } else {
            // 尾插
            exist.addAll(List.of(vals));
        }
        return vals.length;
    }

    /**
     * 弹出value
     *
     * @param key   key
     * @param type  <p> true:lpop
     *              <p> false:rpop
     * @param count 弹出几个元素
     * @return >0 成功
     */
    public String[] pop(String key, boolean type, int count) {
        CacheEntry<LinkedList<String>> entry = (CacheEntry<LinkedList<String>>) maps.get(key);
        // 空处理
        if (entry == null) {
            return new String[0];
        }
        LinkedList<String> exist = entry.getValue();
        if (exist == null) {
            return new String[0];
        }
        // 总长度跟传入的count取一个最小值，包装下标不会溢出
        int len = Math.min(count, exist.size());
        String[] ret = new String[len];
        // 数据弹出
        int index = 0;
        if (type) {
            while (index < len) {
                ret[index++] = exist.removeFirst();
            }
        } else {
            while (index < len) {
                ret[index++] = exist.removeLast();
            }
        }
        return ret;
    }

    /**
     * 获取 list 列表长度
     *
     * @param key list的key
     * @return 长度
     */
    public Integer llen(String key) {
        CacheEntry<LinkedList<String>> entry = (CacheEntry<LinkedList<String>>) maps.get(key);
        if (entry == null) {
            return 0;
        }
        LinkedList<String> exist = entry.getValue();
        if (exist == null) {
            return 0;
        }
        return exist.size();
    }

    /**
     * 获取列表中的元素
     *
     * @param key   key
     * @param index 元素下标
     * @return
     */
    public String lindex(String key, Integer index) {
        CacheEntry<LinkedList<String>> entry = (CacheEntry<LinkedList<String>>) maps.get(key);
        if (entry == null) {
            return null;
        }
        LinkedList<String> exist = entry.getValue();
        if (exist == null) {
            return null;
        }
        if (index >= exist.size()) {
            return null;
        }
        return exist.get(index);
    }

    /**
     * 获取列表指定范围内的元素
     *
     * @param key   key
     * @param start 起始位置
     * @param stop  结束位置
     * @return 元素集合
     */
    public String[] lrange(String key, int start, int stop) {
        if (start > stop) {
            return null;
        }
        CacheEntry<LinkedList<String>> entry = (CacheEntry<LinkedList<String>>) maps.get(key);
        if (entry == null) {
            return null;
        }
        LinkedList<String> exist = entry.getValue();
        if (exist == null) {
            return null;
        }
        int size = exist.size();
        if (start >= size) {
            return null;
        }
        // stop 溢出了使用 list size 覆盖掉
        if (stop >= size) {
           stop = size -1 ;
        }
        // 以 list长度为准
        int len = Math.min(size, (stop - start) + 1);
        String[] ret = new String[len];
        for (int i = 0; i < len; i++) {
            ret[i] = exist.get(start + i);
        }
        return ret;
    }


    // =========================处理 list 类型 end ==================================

    // =========================处理 set 类型 start ==================================

    /**
     * 向集合添加一个或多个成员
     * @param key key
     * @param vals vals
     * @return 添加的个数
     */
    public Integer sadd(String key, String[] vals) {
        if (vals == null || vals.length == 0) {
            return 0;
        }
        CacheEntry<LinkedHashSet<String>> entry = (CacheEntry<LinkedHashSet<String>>) maps.get(key);
        if (entry == null) {
            entry = new CacheEntry<>(new LinkedHashSet<>());
            maps.put(key, entry);
        }
        LinkedHashSet<String> exist = entry.getValue();
        exist.addAll(Arrays.asList(vals));
        return vals.length;
    }

    /**
     * 返回集合中的所有成员
     * @param key key
     * @return 所有成员
     */
    public String[] smembers(String key) {
        CacheEntry<LinkedHashSet<String>> entry = (CacheEntry<LinkedHashSet<String>>) maps.get(key);
        if(entry == null) {
            return new String[0];
        }
        LinkedHashSet<String> exist = entry.getValue();
        return exist.toArray(String[]::new);
    }

    /**
     * 获取集合的成员数
     * @param key key
     * @return 长度
     */
    public Integer scard(String key) {
        CacheEntry<?> entry = maps.get(key);
        if(entry == null) {
            return null;
        }
        LinkedHashSet<?> exist = (LinkedHashSet<?>) entry.getValue();
        return exist.size();
    }

    /**
     * 判断元素是否是集合 key 的成员
     * @param key key
     * @param val val
     * @return 0,1
     */
    public Integer sismember(String key, String val) {
        CacheEntry<LinkedHashSet<String>> entry = (CacheEntry<LinkedHashSet<String>>) maps.get(key);
        if(entry == null) {
            return 0;
        }
        LinkedHashSet<String> exist = entry.getValue();
        return exist.contains(val) ? 1 : 0;
    }

    /**
     * 移除集合中一个或多个成员
     * @param key key
     * @param vals vals
     * @return > 0
     */
    public Integer srem(String key, String[] vals) {
        CacheEntry<LinkedHashSet<String>> entry = (CacheEntry<LinkedHashSet<String>>) maps.get(key);
        if(entry == null) {
            return 0;
        }
        LinkedHashSet<String> exist = entry.getValue();
        return vals==null ? 0 : (int) Arrays.stream(vals)
                .map(exist::remove).filter(x -> x).count();
    }

    /**
     * 移除并返回集合中被删除随机的元素
     * @param key key
     * @param count 批量几个
     * @return 被删除随机的元素
     */
    public String[] spop(String key, int count) {
        CacheEntry<LinkedHashSet<String>> entry = (CacheEntry<LinkedHashSet<String>>) maps.get(key);
        if(entry == null) {
            return new String[0];
        }
        LinkedHashSet<String> exist = entry.getValue();
        if(exist == null) {
            return new String[0];
        }
        int len = Math.min(count, exist.size());
        String[] ret = new String[len];
        int index = 0;
        while(index < len) {
            // 当前数据
            String[] array = exist.toArray(String[]::new);
            // 随机获取元素
            String obj = array[random.nextInt(exist.size())];
            // 删除这个倒霉的元素
            exist.remove(obj);
            // 放到返回数组了
            ret[index ++] = obj;
        }
        return ret;
    }



    // =========================处理 set 类型 end ==================================


    // =========================处理 hash 类型 start ==================================
    /**
     *  将哈希表 key 中的字段 field 的值设为 value 。
     * @param key key
     * @param hkeys hkeys
     * @param hvals hvals
     * @return success number
     */
    public Integer hset(String key, String[] hkeys, String[] hvals) {
        if(hkeys == null || hkeys.length == 0) {
            return 0;
        }
        if(hvals == null || hvals.length == 0) {
            return 0;
        }
        CacheEntry<LinkedHashMap<String, String>> entry = (CacheEntry<LinkedHashMap<String, String>>) maps.get(key);
        if(entry == null) {
            entry = new CacheEntry<>(new LinkedHashMap<>());
            this.maps.put(key, entry);
        }
        LinkedHashMap<String,String> exist = entry.getValue();
        for(int i=0;i<hkeys.length;i++) {
            exist.put(hkeys[i], hvals[i]);
        }
        return (int) Arrays.stream(hkeys).distinct().count();
    }

    /**
     * 获取所有给定字段的值
     * @param key key
     * @param hkeys hkeys
     * @return 值
     */
    public String[] hmget(String key, String[] hkeys) {
        CacheEntry<LinkedHashMap<String, String>> entry = (CacheEntry<LinkedHashMap<String, String>>) maps.get(key);
        if(entry == null) {
            return new String[0];
        }
        LinkedHashMap<String,String> exist = entry.getValue();

        return hkeys==null ? new String[0] : Arrays.stream(hkeys)
                .map(exist::get).toArray(String[]::new);
    }

    /**
     * 获取哈希表中字段的数量
     * @param key key
     * @return 数量
     */
    public Integer hlen(String key) {
        CacheEntry<LinkedHashMap<String, String>> entry = (CacheEntry<LinkedHashMap<String, String>>) maps.get(key);
        if(entry == null) {
            return 0;
        }
        LinkedHashMap<String,String> exist = entry.getValue();
        return exist.size();
    }

    /**
     * 获取存储在哈希表中指定字段的值
     * @param key key
     * @param hkey hkey
     * @return 值
     */
    public String hget(String key, String hkey) {
        CacheEntry<LinkedHashMap<String, String>> entry = (CacheEntry<LinkedHashMap<String, String>>) maps.get(key);
        if(entry == null) {
            return null;
        }
        LinkedHashMap<String,String> exist = entry.getValue();
        return exist.get(hkey);
    }

    /**
     * 获取在哈希表中指定 key 的所有字段和值
     * @param key 指定 key
     * @return 所有字段和值
     */
    public String[] hgetall(String key) {
        CacheEntry<LinkedHashMap<String, String>> entry = (CacheEntry<LinkedHashMap<String, String>>) maps.get(key);
        if(entry == null) {
            return new String[0];
        }
        LinkedHashMap<String,String> exist = entry.getValue();
        return exist.entrySet().stream()
                .flatMap(e -> Stream.of(e.getKey(), e.getValue())).toArray(String[]::new);
    }

    /**
     * 查看哈希表 key 中，指定的字段是否存在
     * @param key key
     * @param hkey hkey
     * @return 0,1
     */
    public Integer hexists(String key, String hkey) {
        CacheEntry<LinkedHashMap<String, String>> entry = (CacheEntry<LinkedHashMap<String, String>>) maps.get(key);
        if(entry == null) {
            return 0;
        }
        LinkedHashMap<String,String> exist = entry.getValue();
        return exist.containsKey(hkey) ? 1 : 0;
    }

    /**
     * 删除一个或多个哈希表字段
     * @param key key
     * @param hkeys hkeys
     * @return 0,delete count
     */
    public Integer hdel(String key, String[] hkeys) {
        CacheEntry<LinkedHashMap<String, String>> entry = (CacheEntry<LinkedHashMap<String, String>>) maps.get(key);
        if(entry == null) {
            return 0;
        }
        LinkedHashMap<String,String> exist = entry.getValue();
        return hkeys==null ? 0 : (int) Arrays.stream(hkeys)
                .map(exist::remove).filter(Objects::nonNull).count();
    }



    // =========================处理 hash 类型 end ==================================

    // =========================处理 zset 类型 start ==================================

    /**
     * 向有序集合添加一个或多个成员，或者更新已存在成员的分数
     * @param key key
     * @param vals vals
     * @param scores 权重
     * @return
     */
    public Integer zadd(String key, String[] vals, double[] scores) {
        CacheEntry<LinkedHashSet<ZsetEntry>> entry = (CacheEntry<LinkedHashSet<ZsetEntry>>) maps.get(key);
        if(entry == null) {
            entry = new CacheEntry<>(new LinkedHashSet<>());
            this.maps.put(key, entry);
        }
        LinkedHashSet<ZsetEntry> exist = entry.getValue();
        for(int i=0;i<vals.length;i++) {
            exist.add(new ZsetEntry(vals[i], scores[i]));
        }
        return vals.length;
    }

    /**
     * 获取有序集合的成员数
     * @param key key
     * @return number
     */
    public Integer zcard(String key) {
        CacheEntry<?> entry = maps.get(key);
        if(entry == null) {
            return 0;
        }
        LinkedHashSet<?> exist = (LinkedHashSet<?>) entry.getValue();
        return exist.size();
    }

    /**
     * 计算在有序集合中指定区间分数的成员数
     * @param key key
     * @param min 开始区间
     * @param max 结束区间
     * @return 数量
     */
    public Integer zcount(String key, double min, double max) {
        CacheEntry<?> entry = maps.get(key);
        if(entry == null) {
            return 0;
        }
        LinkedHashSet<ZsetEntry> exist = (LinkedHashSet<ZsetEntry>) entry.getValue();
        return (int)exist.stream().filter(x -> x.getScore() >= min && x.getScore() <= max).count();
    }

    /**
     * 返回有序集中，成员的分数值
     * @param key key
     * @param val val
     * @return 分数值
     */
    public Double zscore(String key, String val) {
        CacheEntry<?> entry = maps.get(key);
        if(entry == null) {
            return null;
        }
        LinkedHashSet<ZsetEntry> exist = (LinkedHashSet<ZsetEntry>) entry.getValue();
        return exist.stream().filter(x -> x.getValue().equals(val))
                .map(ZsetEntry::getScore).findFirst().orElse(null);
    }

    /**
     * 返回有序集合中指定成员的索引
     * @param key key
     * @param val val
     * @return 索引
     */
    public Integer zrank(String key, String val) {
        CacheEntry<?> entry = maps.get(key);
        if(entry == null) {
            return null;
        }
        LinkedHashSet<ZsetEntry> exist = (LinkedHashSet<ZsetEntry>) entry.getValue();
        Double zscore = zscore(key, val);
        if(zscore == null) {
            return null;
        }
        return (int) exist.stream().filter(x -> x.getScore() < zscore).count();
    }

    /**
     * 移除有序集合中的一个或多个成员
     * @param key key
     * @param vals vals
     * @return success number
     */
    public Integer zrem(String key, String[] vals) {
        CacheEntry<?> entry = maps.get(key);
        if(entry == null) {
            return null;
        }
        LinkedHashSet<ZsetEntry> exist = (LinkedHashSet<ZsetEntry>) entry.getValue();
        return vals==null ? 0 : (int) Arrays.stream(vals)
                .map(x -> exist.removeIf( y -> y.getValue().equals(x)))
                .filter(x -> x).count();
    }


    // =========================处理 zset 类型 end ==================================
}
